package com.example.guava.ratelimiter.aop;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;

import com.example.guava.ratelimiter.annotation.XlRateLimiter;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 限流切面 - 单机限流  CacheBuilder
 * @author zhouxuan
 * @date 2020/5/15 17:14
 */
@Component
@Aspect
@Slf4j
public class RateLimiterAspect {

    /**
     * RateLimiter的过期时间
     */
    Cache<String, RateLimiter> cache = CacheBuilder.newBuilder().maximumSize(1000).build(/*new CacheLoader<String, RateLimiter>() {

                @Override
                public RateLimiter load(String key) throws Exception {
                    return RateLimiter.create(Integer.MAX_VALUE);
                }
            }*/);

    Cache<String, String> keyCache = CacheBuilder.newBuilder().maximumSize(1000).build();

    /**
     * 定义切点 1:通过扫包切入  2：通过指定注解切入
     */
    @Pointcut(value = "@annotation(com.example.guava.ratelimiter.annotation.XlRateLimiter)")
    public void checkPointCut() {

    }

    @ResponseBody
    @Around(value = "checkPointCut()")
    public Object aroundNotice(ProceedingJoinPoint pjp) throws Throwable {
        //获取目标方法的签名
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        //获取目标方法
        Method targetMethod = methodSignature.getMethod();
        if (targetMethod.isAnnotationPresent(XlRateLimiter.class)) {
            XlRateLimiter lxRateLimit = targetMethod.getAnnotation(XlRateLimiter.class);
            String key = lxRateLimit.key();

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();
            String url = request.getRequestURI();
            System.out.println("接口" + key + "--------" + url);
            String value = keyCache.getIfPresent(key);

            if (value == null) {
                keyCache.put(key, url);
            }
            else {
                System.out.println("缓存" + key + "--------" + value);
                if (!url.equals(value)) {
                    System.out.println("key已存在，请重新定义");
                    return "key已存在，请重新定义";
                }
            }
            RateLimiter limiter = cache.getIfPresent(key);
            if (null == limiter) {
                limiter = RateLimiter.create(lxRateLimit.perSecond());
                cache.put(key, limiter);
            }
            //设置失败 请求数量已经到达上线，提示失败
            if (!limiter.tryAcquire(1, 10, TimeUnit.MILLISECONDS)) {
                System.out.println(new Date() + "接口失败");
            }
            else {
                System.out.println(new Date() + "接口成功");
            }
        }
        return pjp.proceed();
    }
}
